//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// File associations.
//

# include "StdAfx.h"
# include "FileAssoc.h"
# include "Reg.h"
# include "Settings.h"

enum {ftiMain = 0, ftiWTR = 1, ftiIndex = 2, ftiRaster = 3, ftiMap2 = 4};

struct file_assoc_t {
	const char * strExt;
	const char * strClass;
	size_t       cIconIdx;
	const char * strDescription;
};

static file_assoc_t g_FileAssoc [] = {
	{".txt", "txtfile",                   -1,         NULL},
	{".mp",  "mpfile",                    ftiMain,    "Polish format"},

	{".img", "imgfile",                   ftiMain,    "Garmin MapSource map"},
	{".rgn", "rgnfile",                   ftiMain,    "Garmin MapSource POI map"},
	{".tdb", "tdbfile",                   ftiIndex,   "Garmin map index"},
	{".mps", "MapSource.Document",        ftiWTR,     "MapSource Document"},
	{".gdb", "GarminGpsDatabase",         ftiWTR,     "Garmin GPS Database"},

	{".shp", "shpfile",                   ftiMain,    "ESRI shapefile"},
	{".mif", "miffile",                   ftiMain,    "MapInfo Interchange file"},

	{".ecw", "ecwfile",                   ftiRaster,  "Enhanced Compressed Wavelet"},
	{".jp2", "jp2file",                   ftiRaster,  "JPEG 2000 image"},

	{".map", "OziExplorer.MapFile",       ftiRaster,  "OziExplorer raster map"},
	{".plt", "OziExplorer.TrackFile",     ftiWTR,     "OziExplorer tracks"},
	{".wpt", "OziExplorer.WaypointsFile", ftiWTR,     "OziExplorer waypoints"},
	{".rte", "OziExplorer.RoutesFile",    ftiWTR,     "OziExplorer routes"},
	{".rt2", "rt2file",                   ftiWTR,     "OziCE route"},

	{".trk", "trkfile",                   ftiWTR,     "Magellan tracks"},

	{".crd", "crdfile",                   ftiMain,    "MapShow map"},
	{".lst", "lstfile",                   ftiMain,    "MapShow map list"},

	{".ard", "ardfile",                   ftiMain,    "MapRoute map"},
//	{".arl", "arlfile",                   ftiMain,    "MapRoute map list"},

	{".wpo", "wpofile",                   ftiWTR,     "Holux waypoints and routes"},
	{".tkl", "tklfile",                   ftiWTR,     "Holux MapShow305 tracks"},

	{".wrt", "wrtfile",                   ftiWTR,     "ALAN Map 500 legacy waypoints and routes"},
	{".wpr", "wprfile",                   ftiWTR,     "ALAN Map 500/600 waypoints and routes"},
	{".tlg", "tlgfile",                   ftiWTR,     "ALAN Map 500 legacy tracks"},
	{".trl", "trlfile",                   ftiWTR,     "ALAN Map 500/600 tracks"},

	{".gpx", "gpxfile",                   ftiWTR,     "GPS eXchange file"},

	{".rus", "rusfile",                   ftiMap2,    "RUSSA map"},
	{".ntm", "ntmfile",                   ftiMap2,    "NaviTel map"},
};

const size_t c_cFileAssocNum = sizeof (g_FileAssoc)/sizeof (g_FileAssoc [0]);

static
void _AssociateFileType (const char * _strExt, const char * _strClass, size_t _cIconIdx, const char * _strDescription) {
	CRegistryKey hExt;
	hExt.Create (HKEY_CLASSES_ROOT, _strExt);
	if (! hExt.IsValid ())
		return;

	// Define the class.
	char strClass [128];
	DWORD dwSize = sizeof (strClass);
	if (
		::RegQueryValueEx (hExt, NULL, NULL, NULL, reinterpret_cast<BYTE *> (strClass), & dwSize) == ERROR_SUCCESS &&
		dwSize > 1
	)
		_strClass = strClass;
	else
		hExt.SetValue (NULL, _strClass);

	// Open the class' key.
	CRegistryKey hClass;
	hClass.Create (HKEY_CLASSES_ROOT, _strClass);
	if (! hClass.IsValid ())
		return;

	if (_strDescription) {
		dwSize = 0;
		::RegQueryValueEx (hClass, NULL, NULL, NULL, NULL, & dwSize);
		if (dwSize == 0)
			hClass.SetValue (NULL, _strDescription);
	}

	// \Shell
	CRegistryKey hShell;
	hShell.Create (hClass, "Shell");
	if (hShell.IsValid ()) {
		// Delete the old key (with space in the program title).
		::SHDeleteKey (hShell, "Open with GPSMap Edit");

		// Shell\Open
		CRegistryKey hOpen;
		hOpen.Create (hShell, "Open with GPSMapEdit");
		if (hOpen.IsValid ()) {
			// Shell\Open\Command
			CRegistryKey hCommand;
			hCommand.Create (hOpen, "Command");
			if (hCommand.IsValid ()) {
				char strStart [MAX_PATH + 10];
				::GetModuleFileName (NULL, strStart, MAX_PATH);
				::PathQuoteSpaces (strStart);
				::strcat (strStart, " \"%1\"");
				hCommand.SetValue (NULL, strStart);
			}
		}

/*		if (::strcmp (_strClass, "imgfile") == 0) {
			// Shell\Register in MapSource
			CRegistryKey hRegister;
			hRegister.Create (hShell, "Register in MapSource");
			if (hRegister.IsValid ()) {
				// Shell\Register\Command
				CRegistryKey hCommand;
				hCommand.Create (hRegister, "Command");
				if (hCommand.IsValid ()) {
					char strStart [MAX_PATH + 10];
					::GetModuleFileName (NULL, strStart, MAX_PATH);
					::PathQuoteSpaces (strStart);
					::strcat (strStart, " /registerimg \"%1\"");
					hCommand.SetValue (NULL, strStart);
				}
			}
		}*/

		if (::strcmp (_strClass, "mpfile") == 0) {
			// Shell\Open with Notepad
			CRegistryKey hRegister;
			hRegister.Create (hShell, "Open with Notepad");
			if (hRegister.IsValid ()) {
				// Shell\Register\Command
				CRegistryKey hCommand;
				hCommand.Create (hRegister, "Command");
				if (hCommand.IsValid ())
					hCommand.SetValue (NULL, "notepad.exe \"%1\"");
			}
		}
	}

	if (_cIconIdx != -1) {
		// \DefaultIcon
		CRegistryKey hIcon;
		hIcon.Create (hClass, "DefaultIcon");
		if (hIcon.IsValid ()) {
			char strCurrentIcon [MAX_PATH + 10] = "";
			hIcon.QueryValue (NULL, strCurrentIcon, sizeof (strCurrentIcon));
			::PathParseIconLocation (strCurrentIcon);
			::PathStripPath (strCurrentIcon);

			char strThisIcon [MAX_PATH];
			::GetModuleFileName (NULL, strThisIcon, MAX_PATH);
			::PathStripPath (strThisIcon);

			if (strCurrentIcon [0] == '\0' || ::stricmp (strCurrentIcon, strThisIcon) == 0) {
				char strIcon [MAX_PATH + 10];
				::GetModuleFileName (NULL, strIcon, MAX_PATH);
				::PathQuoteSpaces (strIcon);
				::strcat (strIcon, ",");
				::itoa (_cIconIdx, strIcon + ::strlen (strIcon), 10);
				hIcon.SetValue (NULL, strIcon);
			}
		}
	}
}

static
void _RemoveFileAssociation (const char * _strClass) {
	// Open the class' key.
	CRegistryKey hClass;
	hClass.Open (HKEY_CLASSES_ROOT, _strClass);
	if (! hClass.IsValid ())
		return;

	// \Shell
	CRegistryKey hShell;
	hShell.Create (hClass, "Shell");
	if (! hShell.IsValid ())
		return;

	::SHDeleteKey (hShell, "Open with GPSMapEdit");
}

void UpdateFileAssociations (bool _bDeepUpdate) {
	//
	// Update associations.
	//

	for (size_t c = 0; c < c_cFileAssocNum; ++ c)
		_AssociateFileType (
			g_FileAssoc [c].strExt,
			g_FileAssoc [c].strClass,
			g_FileAssoc [c].cIconIdx,
			g_FileAssoc [c].strDescription
		);

	if (_bDeepUpdate)
		// Notify Shell about change of file associations.
		::SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
}

void RemoveFileAssociations () {
	// Remove associations.
	for (size_t c = 0; c < c_cFileAssocNum; ++ c)
		_RemoveFileAssociation (g_FileAssoc [c].strClass);

	// Notify Shell about change of file associations.
	::SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
}